
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;

public class Polygon {

    final static int UNIT = 25;
    final int COS90 = 0;
    final int SIN90 = 1;
    boolean alignmentSwitch = false;
    float x1 = 0, x2 = Float.MAX_VALUE, y1 = 0, y2 = Float.MAX_VALUE;
    boolean active = true;
    private int x, y;
    private Cube[] BLOCKS = new Cube[4];
    private Cube[] NEW_BLOCKS = new Cube[4];
    private Point rotationCenter;
    private char type;

    Polygon(int x, int y, Color color, char type) {
        this.x = x;
        this.y = y;
        this.type = type;
        switch (type) {
            case 'I':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x, y + UNIT, color);
                BLOCKS[2] = new Cube(x, y + UNIT + UNIT, color);
                BLOCKS[3] = new Cube(x, y + UNIT + UNIT + UNIT, color);
                break;
            case 'L':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x + UNIT + UNIT, y, color);
                BLOCKS[3] = new Cube(x, y - UNIT, color);
                break;
            case 'J':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x + UNIT + UNIT, y, color);
                BLOCKS[3] = new Cube(x + UNIT + UNIT, y - UNIT, color);
                break;
            case 'Z':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x + UNIT, y + UNIT, color);
                BLOCKS[3] = new Cube(x + UNIT + UNIT, y + UNIT, color);
                break;
            case 'T':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x + UNIT + UNIT, y, color);
                BLOCKS[3] = new Cube(x + UNIT, y - UNIT, color);
                break;
            case 'S':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x, y + UNIT, color);
                BLOCKS[3] = new Cube(x - UNIT, y + UNIT, color);
                break;
            case 'O':
                BLOCKS[0] = new Cube(x, y, color);
                BLOCKS[1] = new Cube(x + UNIT, y, color);
                BLOCKS[2] = new Cube(x, y + UNIT, color);
                BLOCKS[3] = new Cube(x + UNIT, y + UNIT, color);
                break;
        }
    }

    public void draw(Graphics2D graphics2D) {
        for (int a = 0; a < BLOCKS.length; a++) {
            BLOCKS[a].draw(graphics2D);
        }
    }

    public void calculateRotation() {
        if (type != 'O') {
//        System.arraycopy(BLOCKS, 0, NEW_BLOCKS, 0, BLOCKS.length);
            NEW_BLOCKS[0] = new Cube(BLOCKS[0]);
            NEW_BLOCKS[1] = new Cube(BLOCKS[1]);
            NEW_BLOCKS[2] = new Cube(BLOCKS[2]);
            NEW_BLOCKS[3] = new Cube(BLOCKS[3]);

            rotationCenter = getCenter(NEW_BLOCKS);
            for (int a = 0; a < NEW_BLOCKS.length; a++) {
                Cube cube = NEW_BLOCKS[a];
                //rotate each cube
                Point xy = transformToOriginAndRotate(cube.getX(), cube.getY(), rotationCenter);
                cube.setX(xy.getX());
                cube.setY(xy.getY());
            }
            alignmentSwitch = !alignmentSwitch;//TODO:GENERICS!!
        }
    }

    public void move(int direction) {
        rotationCenter = getCenter(BLOCKS);
        for (int a = 0; a < BLOCKS.length; a++) {
            Cube cube = BLOCKS[a];
            switch (direction) {
                case Main.DOWN:
                    if (y1 < Main.HEIGHT - UNIT) {
                        cube.setY(cube.getY() + UNIT);
                    } else {
                        this.setInactive();
                    }
                    break;
                case Main.LEFT:
                    if (x2 > UNIT) {
                        cube.setX(cube.getX() - UNIT);
                    }
                    break;
                case Main.RIGHT:
                    if (x1 < Main.FIELD_WIDTH) {
                        cube.setX(cube.getX() + UNIT);
                    }
                    break;
            }
        }
    }

    public Cube[] getCubes() {
        return BLOCKS;
    }

    public Cube[] getNewCubes() {
        return NEW_BLOCKS;
    }

    public boolean isActive() {
        return active;
    }

    public void setInactive() {
        this.active = false;
    }

    Point getCenter(Cube[] blocks) {
        x1 = 0;
        x2 = Float.MAX_VALUE;
        y1 = 0;
        y2 = Float.MAX_VALUE;
        for (int a = 0; a < blocks.length; a++) {
            Cube cube = blocks[a];
            if (cube.getX() > x1) {//largest x
                x1 = cube.getX();
            }
            if (cube.getX() < x2) {//smallest x
                x2 = cube.getX();
            }
            if (cube.getY() > y1) {//largest y
                y1 = cube.getY();
            }
            if (cube.getY() < y2) {//smallest y
                y2 = cube.getY();
            }
        }
        Point center = new Point((x1 + x2) / 2, (y1 + y2) / 2);
        return center;
    }

    private Point transformToOriginAndRotate(int x, int y, Point rotation) {
        int deltaX = rotation.getX();
        int deltaY = rotation.getY();

        //transform to origin
        x -= deltaX;
        y -= deltaY;

        //rotate clockwise
        int tempX = x;
        x = -y * -SIN90;
        y = tempX * -SIN90;

        //transform bacjk
        x += deltaX;
        y += deltaY;

        //align
        if (alignmentSwitch) {
            x -= (x % UNIT);//TODO:align alignments
            y += UNIT - (y % UNIT);
        } else {
            x += UNIT - (x % UNIT);
            y -= (y % UNIT);
        }

        return new Point(x, y);
    }

    void applyRotation() {
        System.arraycopy(NEW_BLOCKS, 0, BLOCKS, 0, NEW_BLOCKS.length);
    }

    void restore() {
        NEW_BLOCKS = new Cube[4];
        alignmentSwitch = !alignmentSwitch;
    }
}

class Point {

    private int x, y;

    Point(float x, float y) {
        this.x = (int) x;
        this.y = (int) y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

class Cube {

    private int x, y;
    private RoundRectangle2D rectangle;
    private Color color;

    Cube(Cube cube) {
        this.x = cube.getX();
        this.y = cube.getY();
        this.color = cube.getColor();
        rectangle = new RoundRectangle2D.Float(x, y, Polygon.UNIT, Polygon.UNIT, 9, 9);
    }

    Cube(int x, int y, Color color) {
        this.x = x;
        this.y = y;
        this.color = color;
        rectangle = new RoundRectangle2D.Float(x, y, Polygon.UNIT, Polygon.UNIT, 9, 9);
    }

    public int getX() {
        return x;
    }

    public int getUnitX() {
        return x / Polygon.UNIT;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getUnitY() {
        return y / Polygon.UNIT;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public void draw(Graphics2D graphics2D) {
        if (color != Main.BACKGROUND_COLOR) {
            rectangle = new RoundRectangle2D.Float(x, y, Polygon.UNIT, Polygon.UNIT, 9, 9);
            graphics2D.setPaint(color);
            graphics2D.fill(rectangle);
        }
    }
}